package com.sjqi.demo;

import com.mysql.jdbc.StringUtils;
import com.sjqi.demo.po.InvoiceEntity;
import org.apache.commons.dbcp.BasicDataSource;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.*;
import java.util.*;

/**
 * @author qishaojun
 * v1版本
 * 1.获取连接 在原有jdbc的基础上抽取出连接池，数据库配置信息放到properties中。 结局掉硬编码，频繁获取连接的问题
 * 2.执行sql  将sql抽取到配置文件中，根据key 匹配具体sql， 解决sql硬编码问题
 * 参数设置 需要支持多种类型
 * 3.匹配结果集
 */

public class MybatisV1 {
    private Properties properties = new Properties();

    @Test
    public void testJdbc() {
        this.loadProperties("jdbc.properties");

        List<InvoiceEntity> list = this.selectList("queryInvoiceById", 10892L);
        System.out.println(list);
    }

    private <T> List<T> selectList(String statementId, Object param) {
        List<T> resultList = new ArrayList<>();
        Connection connection = null;
        PreparedStatement pStatement = null;
        ResultSet rs = null;
        try {
            //抽取出数据库的配置信息
            BasicDataSource dataSource = new BasicDataSource();
            dataSource.setDriverClassName(properties.getProperty("db.driver"));
            dataSource.setUrl(properties.getProperty("db.url"));
            dataSource.setUsername(properties.getProperty("db.username"));
            dataSource.setPassword(properties.getProperty("db.password"));
            connection = dataSource.getConnection();

            //抽取出sql
            String sql = properties.getProperty("db.sql." + statementId);
            if (StringUtils.isNullOrEmpty(sql)) {
                throw new IllegalArgumentException("can not find sql by statementId :" + statementId);
            }
            pStatement = connection.prepareStatement(sql);
            //基本类型直接设置
            if (param instanceof Integer || param instanceof Long || param instanceof String) {
                pStatement.setObject(1, param);
            } else if (param instanceof Map) {
                Map<String, Object> paramMap = (Map<String, Object>) param;
                String[] columns = properties.getProperty("db.sql." + statementId + ".columnnames").split(",");
                for (int i = 0; i < columns.length; i++) {
                    Object paramObj = paramMap.get(columns[i]);
                    pStatement.setObject(i + 1, paramObj);
                }
            } else {
                //TODO:POJO
            }
            rs = pStatement.executeQuery();

            String resultType = properties.getProperty("db.sql." + statementId + ".resulttype");
            Class<?> resultTypeClass = Class.forName(resultType);
            Constructor<?> constructor = resultTypeClass.getDeclaredConstructor();
            Object result = null;
            while (rs.next()) {
                result = constructor.newInstance();
                ResultSetMetaData resultSetMetaData = rs.getMetaData();
                int columnCount = resultSetMetaData.getColumnCount();
                for (int i = 0; i < columnCount; i++) {
                    String fieldName = resultSetMetaData.getColumnName(i + 1);
                    Field field = null;
                    try {
                        //TODO:为了处理表字段没有匹配的属性时 暂时抛出异常
                        field = resultTypeClass.getDeclaredField(fieldName);
                    } catch (NoSuchFieldException e) {
                    }
                    if (null != field) {
                        field.setAccessible(true);
                        field.set(result, rs.getObject(fieldName));
                    }

                }
                resultList.add((T) result);
            }

        } catch (SQLException | ClassNotFoundException | IllegalAccessException | InstantiationException | NoSuchMethodException | InvocationTargetException e) {
            e.printStackTrace();
        } finally {
            if (null != rs) {
                try {
                    rs.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != pStatement) {
                try {
                    pStatement.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (null != connection) {
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
        return resultList;
    }

    /**
     * 加载配置文件
     *
     * @param fileName fileName
     */
    private void loadProperties(String fileName) {
        InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(fileName);
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != inputStream) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}
